package com.alpha.eceasy.mall.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.alpha.eceasy.auth.LoginUser;
import com.alpha.eceasy.auth.UserLoginDTO;
import com.alpha.eceasy.exception.BizException;
import com.alpha.eceasy.exception.ErrorCodeEnum;
import com.alpha.eceasy.extension.BaseServiceImpl;
import com.alpha.eceasy.mall.api.dto.UpdatePasswordDTO;
import com.alpha.eceasy.mall.api.entity.MallCustomer;
import com.alpha.eceasy.mall.mapper.MallCustomerMapper;
import com.alpha.eceasy.mall.service.MallCustomerService;
import com.alpha.eceasy.mall.util.SecurityUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Service
public class MallCustomerServiceImpl extends BaseServiceImpl<MallCustomerMapper, MallCustomer> implements MallCustomerService {
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public String login(UserLoginDTO dto) {
        AbstractAuthenticationToken authenticationToken;
        Map<String, Object> params = new HashMap<>();
        params.put("uuid", IdUtil.simpleUUID());
        params.put("userLoginType", dto.userLoginType());
        switch (dto.userLoginType()) {
            // 账号密码登录
            case ACCOUNT_AND_PASSWORD -> {
                // 创建Authentication对象
                authenticationToken = new UsernamePasswordAuthenticationToken(dto.userAccount(), dto.userPassword());
                // 调用AuthenticationManager的authenticate方法进行认证
                Authentication authenticate = authenticationManager.authenticate(authenticationToken);
                LoginUser<MallCustomer> loginUser = SecurityUtils.getLoginUser(authenticate);
                params.put("principal", dto.userAccount());
                params.put("credentials", dto.userPassword());
                // 将用户的数据存储到Redis中
                stringRedisTemplate.boundValueOps("login_user_info:" + loginUser.getUserInfo().getUsername())
                        .set(JSONUtil.toJsonStr(loginUser.getUserInfo()));
            }
            case PHONE_AND_CODE -> {
            }
            // 开放token换取
            case OPEN_TOKEN -> params.put("openToken", dto.token());
            default -> throw new BizException(ErrorCodeEnum.BAD_REQUEST);
        }

        // 生成JWT令牌并进行返回
        String token = JWTUtil.createToken(params, JWTSignerUtil.none());
        log.info("生成JWT令牌：{}", token);
        return token;
    }

    @Override
    public Boolean logout() {
        // TODO 未清除上下文信息，待完善
        // 获取当前登录用户，删除Redis中的用户数据
        stringRedisTemplate.delete("login_user_info:" + SecurityUtils.getUserInfo().getUsername());
        return true;
    }

    @Override
    public MallCustomer info() {
        try {
            return SecurityUtils.getUserInfo();
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public boolean updateInfo(MallCustomer entity) {
        // 获取当前登录用户
        LoginUser<MallCustomer> loginUser = SecurityUtils.getLoginUser();
        MallCustomer sysUser = loginUser.getUserInfo();
        // 取出id
        Long userId = sysUser.getId();
        // 设置要更新的用户id
        entity.setId(sysUser.getId());
        // 不能修改用户名和密码
        entity.setUsername(null);
        entity.setPassword(null);
        // 更新用户信息
        this.updateById(entity);
        // 获取刚刚更新的用户
        entity = baseMapper.selectById(userId);
        // 更新上下文中的用户信息
        stringRedisTemplate.boundValueOps("login_user_info:" + sysUser.getUsername()).set(JSONUtil.toJsonStr(entity));
        loginUser.setUserInfo(entity);
        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, loginUser.getPassword()));
        // 再重新登录
        return true;
    }

    @Override
    public boolean updateInfoPassword(UpdatePasswordDTO dto) {
        // 获取当前登录用户
        MallCustomer sysUser = SecurityUtils.getUserInfo();
        // 创建Authentication对象
        AbstractAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), dto.oldPassword());
        // 调用AuthenticationManager的authenticate方法进行认证
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        // 更新用户信息
        sysUser.setPassword(passwordEncoder.encode(dto.newPassword()));
        this.updateById(sysUser);
//        // 更新上下文中的用户信息
//        stringRedisTemplate.boundValueOps("login_user_info:" + sysUser.getUsername()).set(JSONUtil.toJsonStr(sysUser));
//        SecurityContextHolder.getContext().setAuthentication(authenticate);
        // 再重新登录
        return this.logout();
    }

    @Override
    public boolean save(MallCustomer entity) {
        if (Objects.nonNull(baseMapper.selectOne(Wrappers.<MallCustomer>lambdaQuery()
                .eq(MallCustomer::getUsername, entity.getUsername())))) {
            throw new BizException(ErrorCodeEnum.USER_EXIST);
        }
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        entity.setName(entity.getLastName() + " " + entity.getFirstName());
        return super.save(entity);
    }

    @Override
    public boolean updateByGuid(MallCustomer entity) {
        if (StrUtil.isNotBlank(entity.getPassword())) {
            entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        }
        return super.updateByGuid(entity);
    }

    public MallCustomer getByCustomerName(String customerName) {
        return this.getOne(Wrappers.<MallCustomer>lambdaQuery().eq(MallCustomer::getName, customerName), false);
    }
}
